package cn.birdbaby.plugins.common;

import com.intellij.openapi.application.ReadAction;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Computable;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.ThrowableRunnable;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * @author llorando 7/8/24 11:05 am
 */
public class CommonUtils {
    public static List<PsiElement> collectGenElement(PsiFile psiFile) {
        List<PsiElement> genElement = new ArrayList<>();
        ReadAction.compute(() -> {
            Collection<PsiElement> original = PsiTreeUtil.findChildrenOfAnyType(psiFile, PsiAnnotation.class, PsiImportStatement.class);
            for (PsiElement element : original) {
                if (element instanceof PsiAnnotation) {
                    PsiAnnotation annotation = (PsiAnnotation) element;
                    PsiJavaCodeReferenceElement nameReferenceElement = annotation.getNameReferenceElement();
                    String referenceName = nameReferenceElement.getReferenceName();

                    if (StringUtils.startsWithIgnoreCase(referenceName, "Gen")) {
                        genElement.add(element);
                    }
                } else {
                    PsiImportStatement importStatement = (PsiImportStatement) element;
                    String qualifiedName = importStatement.getQualifiedName();
                    if (qualifiedName.startsWith("cn.birdbaby.codegen.processor")) {
                        genElement.add(element);
                    }
                }
            }
            return true;
        });
        return genElement;
    }

    /**
     * 再同一个groupId下面对一组文件执行一批操作，以方便批次回退
     * @param project
     * @param groupId
     * @param computable
     * @param <T>
     * @throws T
     */
    public static <T extends Throwable> void processWithGroupId(Project project, String groupId, ThrowableRunnable<T> computable) throws T {
        WriteCommandAction.writeCommandAction(project)
                .withGroupId(groupId)
                .run(computable);
    }

    public static boolean isEntity(PsiFile psiFile){
        if(!(psiFile instanceof PsiJavaFile)) return false;
        Collection<PsiAnnotation> psiAnnotations = ReadAction.compute(() -> PsiTreeUtil.findChildrenOfAnyType(psiFile, PsiAnnotation.class));
        if (CollectionUtils.isEmpty(psiAnnotations)) return false;
        for (PsiAnnotation psiAnnotation : psiAnnotations) {
            String referenceName = ReadAction.compute(() -> {
                PsiJavaCodeReferenceElement nameReferenceElement = psiAnnotation.getNameReferenceElement();
                return nameReferenceElement.getReferenceName();
            });

            if (StringUtils.startsWithIgnoreCase(referenceName, "Entity")) {
                return true;
            }

        }
        return false;
    }

    public static boolean shouldAddGen(PsiFile psiFile) {
        if(!(psiFile instanceof PsiJavaFile)) return false;
        Collection<PsiAnnotation> psiAnnotations = ReadAction.compute(() -> PsiTreeUtil.findChildrenOfAnyType(psiFile, PsiAnnotation.class));
        boolean hasEntity = false;
        boolean hasGen = false;
        if (CollectionUtils.isEmpty(psiAnnotations)) return false;
        for (PsiAnnotation psiAnnotation : psiAnnotations) {
            String referenceName = ReadAction.compute(() -> {
                PsiJavaCodeReferenceElement nameReferenceElement = psiAnnotation.getNameReferenceElement();
                return nameReferenceElement.getReferenceName();
            });

            if (StringUtils.startsWithIgnoreCase(referenceName, "Entity")) {
                hasEntity = true;
            }
            if (StringUtils.startsWithIgnoreCase(referenceName, "Gen")) {
                return false;
            }
        }
        return hasEntity && !hasGen;
    }

}
